package com.orange.common.utils;

import com.orange.common.annotation.NotRepeatSubmit;
import com.orange.common.enums.ResultCodeEnum;
import com.orange.common.exception.ApiSecurityException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;

import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * ClassName:ApiUtil
 * Package:com.ywf.springbootmydemo.Utils
 * Description:
 *
 * @Date:2020/7/11 22:44
 * @Author:YWF
 */
public class ApiUtil {

    protected final static Logger logger = LoggerFactory.getLogger(ApiUtil.class);

    /**
     * 按参数名升续拼接参数
     * @param request
     * @return
     */
    public static String concatSignString(HttpServletRequest request) {
        Map<String, String> paramterMap = new HashMap<>();
        request.getParameterMap().forEach((key, value) -> paramterMap.put(key, value[0]));
        // 按照key升续排序，然后拼接参数
        Set<String> keySet = paramterMap.keySet();
        String[] keyArray = keySet.toArray(new String[keySet.size()]);
        Arrays.sort(keyArray);
        StringBuilder sb = new StringBuilder();
        for (String k : keyArray) {
            // 或略掉的字段
            if (k.equals("sign")) {
                continue;
            }
            if (paramterMap.get(k).trim().length() > 0) {
                // 参数值为空，则不参与签名
                sb.append(k).append("=").append(paramterMap.get(k).trim()).append("&");
            }
        }

        return sb.toString();
    }

    public static String concatSignString(Map<String, String> map) {
        Map<String, String> paramterMap = new HashMap<>();
        map.forEach((key, value) -> paramterMap.put(key, value));
        // 按照key升续排序，然后拼接参数
        Set<String> keySet = paramterMap.keySet();
        String[] keyArray = keySet.toArray(new String[keySet.size()]);
        Arrays.sort(keyArray);
        StringBuilder sb = new StringBuilder();
        for (String k : keyArray) {
            if (paramterMap.get(k).trim().length() > 0) {
                // 参数值为空，则不参与签名
                sb.append(k).append("=").append(paramterMap.get(k).trim()).append("&");
            }
        }
        return sb.toString();
    }

    /**
     * 获取方法上的@NotRepeatSubmit注解
     * @param handler
     * @return
     */
    public static NotRepeatSubmit getNotRepeatSubmit(Object handler) {
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            Method method = handlerMethod.getMethod();
            NotRepeatSubmit annotation = method.getAnnotation(NotRepeatSubmit.class);
            return annotation;
        }
        return null;
    }

    /**
     * 标准化请求路径
     * @param path
     * @return
     */
    public static String normalizePath(String path) {
        // 移除重复的斜杠
        String normalized = path.replaceAll("/+", "/");
        // 确保路径以单个斜杠开头
        if (!normalized.startsWith("/")) {
            normalized = "/" + normalized;
        }
        // 移除末尾的斜杠（除非是根路径）
        if (normalized.length() > 1 && normalized.endsWith("/")) {
            normalized = normalized.substring(0, normalized.length() - 1);
        }
        return normalized;
    }

    /**
     * 简易的限流
     *      最终需要根据Redis + Lua 脚本实现，这是临时的方法
     *      这个方法不区分用户，同时有10个用户同一个客户端访问同一个方法会直接导致无法访问
     * @param request
     * @return
     */
    public static String generateRateLimitKey(HttpServletRequest request) {
        // 获取并规范化请求路径
        String requestURI = request.getRequestURI();
        String normalizedUri = normalizePath(requestURI);
        StringBuilder baseKey = new StringBuilder("rate_limit:");
        baseKey.append(normalizedUri);
        String clientIP = IpUtil.getLocalHostIP();
        if (clientIP != null) {
            baseKey.append(":").append(clientIP);
        }
        return baseKey.toString();
    }



    /**
     * 读取输入流的数据
     *
     * @param inputStream
     * @return
     * @throws IOException
     */
    public static byte[] readBytes(InputStream inputStream) throws IOException {
        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
        byte[] data = new byte[4096]; // 4KB 缓冲区
        int bytesRead;
        while ((bytesRead = inputStream.read(data, 0, data.length)) != -1) {
            buffer.write(data, 0, bytesRead);
        }
        return buffer.toByteArray();
    }

}
